package com.example.core.shiroLogin;
import com.example.core.shiroLogin.DTO.UserDTO;
import com.example.core.shiroLogin.service.ShiroLoginService;
import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;


import java.util.HashSet;
import java.util.Set;

/**
 * @ClassName CustomRealm
 * @Author zhangzhaoyang
 * @Date 2019/10/16 10:
 * 将 customRealm的实例化交给spring去管理，当然这里也可以利用注解的方式去注入。
 * 说明：
 * 自定义的Realm类继承AuthorizingRealm类，并且重载doGetAuthorizationInfo和doGetAuthenticationInfo两个方法。
 * doGetAuthorizationInfo： 权限认证，即登录过后，每个身份不一定，对应的所能看的页面也不一样。
 * doGetAuthenticationInfo：身份认证。即登录通过账号和密码验证登陆人的身份信息。
 * 版权声明：本文为CSDN博主「我是你妹她哥」的原创文章，遵循 CC 4.0 BY-SA 版权协议，转载请附上原文出处链接及本声明。
 * 原文链接：https://blog.csdn.net/bicheng4769/article/details/86668209
 **/
public class CustomRealm extends AuthorizingRealm{

    @Autowired
    protected ShiroLoginService shiroLoginService;

    /**
     * 主要是用于当前登录用户授权
     * 鉴权
     * 鉴权是从数据库中获取的
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println("=====进入角色授权======");
        String username = (String) SecurityUtils.getSubject().getPrincipal();
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        Set<String> stringSet = new HashSet<>();
        stringSet.add("user:show");
        stringSet.add("user:admin");
        info.setStringPermissions(stringSet);
        return info;
    }

    /**
     * 这里可以注入userService,为了方便演示，我就写死了帐号了密码
     * private UserService userService
     * 获取即将需要认证的信息
     * 该方法是进行用户验证的
     */

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        System.out.println("-------身份认证方法--------"+authenticationToken);
        //获取基于用户名和密码的令牌
        //实际上这个token是从UserResource面currentUser.login(token)传过来的
        //两个token的引用都是一样的
        UsernamePasswordToken token = (UsernamePasswordToken)authenticationToken;
        System.out.println("验证当前Subject时获取到token为" + ReflectionToStringBuilder.toString(token, ToStringStyle.MULTI_LINE_STYLE));
//        用户的登陆账户
        String userName = (String) authenticationToken.getPrincipal();
//用户输入的密码
        String userPwd = new String((char[]) authenticationToken.getCredentials());
        // 从数据库中获取还用户名对应的user
        UserDTO resultUserPwd = shiroLoginService.queryUserPassword(userPwd);




        //根据用户名从数据库获取密码===解密之前从数据库中获取===
//        String password = "Vm10YVlWVXhUblJXYmtwUFZsWmFXRlpyVWtKUFVUMDk=";
//        ===密码加密后===
        String enCode = EncryptionUtil.encode(resultUserPwd.getSalt());
//        ===密码加密后再进行解密 ===
        String deCode = EncryptionUtil.decode(resultUserPwd.getSalt());
        System.out.println("===数据库里的密文=== : " + userPwd );
        System.out.println("===输入:"+userPwd+"的密码加密后=== : " + enCode );
        System.out.println("===密码解密还原后方法 ===: " + deCode );



        if (userName == null || "".equals(userName)) {
            throw new AccountException("用户名不正确");
        } else if (!userPwd.equals( deCode )) {
            throw new AccountException("密码不正确");
        }
        System.out.println("-------用户："+userName+"==密码=="+userPwd+"===="+getName().toString());
        return new SimpleAuthenticationInfo(userName, deCode, getName());

    }

    /**
     * customRealm初始化的时候耶需要做一些改变
     * @return
     */
    @Bean
    public CustomRealm customRealm() {
        CustomRealm customRealm = new CustomRealm();
        // 告诉realm,使用credentialsMatcher加密算法类来验证密文
        customRealm.setCredentialsMatcher(new HashedCredentialsMatcher());
        customRealm.setCachingEnabled(false);
        return customRealm;
    }

    /**
     * MD5  密码采用加密方式进行验证
     * @param username
     * @param pwd
     * @return String
     */
//    public static String MD5Pwd(String username, String pwd) {
//        // 加密算法MD5
//        // salt盐 username + salt
//        // 迭代次数
//        String md5Pwd = new SimpleHash("MD5", pwd,
//                ByteSource.Util.bytes(username + "salt"), 2).toHex();
//        return md5Pwd;
//    }

}
